package presentation.control;

import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import java.util.logging.Logger;

import javax.swing.JInternalFrame;
import javax.swing.JOptionPane;
import javax.swing.JTable;

import presentation.data.BrowseSelectData;
import presentation.data.CheckoutData;
import presentation.data.DataUtil;
import presentation.data.MessagesUtil;
import presentation.gui.CartItemsWindow;
import presentation.gui.EbazaarMainFrame;
import presentation.gui.FinalOrderWindow;
import presentation.gui.PaymentWindow;
import presentation.gui.ShipAddressesWindow;
import presentation.gui.ShippingBillingWindow;
import presentation.gui.TermsWindow;
import usecasecontrol.ApplicationUtil;
import usecasecontrol.CheckoutController;
import business.SessionCache;
import business.exceptions.BackendException;
import business.exceptions.BusinessException;
import business.exceptions.ParseException;
import business.exceptions.RuleException;
import business.exceptions.UIException;
import business.externalinterfaces.Address;
import business.externalinterfaces.CreditCard;
import business.externalinterfaces.CustomerConstants;
import business.externalinterfaces.CustomerProfile;
import business.externalinterfaces.CustomerSubsystem;
import business.shoppingcartsubsystem.ShoppingCartSubsystemFacade;
import business.util.CustomerUtil;

public class CheckoutUIControl {
	private static final Logger LOG = Logger.getLogger(CheckoutUIControl.class
			.getPackage().getName());
	
	private CheckoutData data = CheckoutData.getInstance();
	private BrowseSelectData bsData = BrowseSelectData.getInstance();
	private CheckoutController usecaseControl = new CheckoutController();
	private static final CheckoutUIControl INSTANCE = new CheckoutUIControl();
	
	class ProceedToCheckoutListener implements ActionListener, Callback {
		/**
		 * This method populates the shipping billing window with the default
		 * address data for this customer. Retrieves the customer name and
		 * default shipping and billing addresses from customer subsystem
		 * interface. These values should have been loaded into the Customer
		 * subsystem at login.
		 */
		public void doUpdate() {
			CustomerProfile custProfile = data.getCustomerProfile();
			Address defaultShipAddress = data.getDefaultShipAddress();
			Address defaultBillAddress = data.getDefaultBillAddress();
			/*
			shippingBillingWindow.setShippingAddress(custProfile.getFirstName()
					+ " " + custProfile.getLastName(),
					defaultShipAddress.getStreet1(),
					defaultShipAddress.getCity(),
					defaultShipAddress.getState(), defaultShipAddress.getZip());
			shippingBillingWindow.setBillingAddress(custProfile.getFirstName()
					+ " " + custProfile.getLastName(),
					defaultBillAddress.getStreet1(),
					defaultBillAddress.getCity(),
					defaultBillAddress.getState(), defaultBillAddress.getZip());*/
			EbazaarMainFrame.getInstance().getDesktop()
					.add(shippingBillingWindow);
			shippingBillingWindow.setVisible(true);
		}

		public void actionPerformed(ActionEvent evt) {
			cartItemsWindow.setVisible(false);
			
			/* check that cart is not empty before going to next screen */	
			boolean rulesOk = true;
			try {
				usecaseControl.runShoppingCartRules();
			} catch (RuleException e) {
				//in initial application, rules will fail -- uncomment when ready
				
				/*
				rulesOk = false;
				LOG.warning("A RuleException was thrown: " + e.getMessage());
				MessagesUtil.displayErrorMsg(cartItemsWindow, e.getMessage());
				cartItemsWindow.setVisible(true);*/
			} catch (BusinessException e) {
				rulesOk = false;
				MessagesUtil.displayErrorMsg(cartItemsWindow, MessagesUtil.GENERAL_ERR_MSG);
				cartItemsWindow.setVisible(true);
			}

			if (rulesOk) {
				boolean isLoggedIn = data.isLoggedIn();
				shippingBillingWindow = new ShippingBillingWindow();
				if (!isLoggedIn) {
					LoginUIControl loginControl = new LoginUIControl(shippingBillingWindow, cartItemsWindow, this);
					loginControl.startLogin();
				} else {
					doUpdate();
				}			
			}
		}
	}
	
	// This listener responds to request to see ship address options
	class SelectShipButtonListener implements ActionListener {
		public void actionPerformed(ActionEvent evt) {
			shippingBillingWindow.setVisible(false);
			ShipAddressesWindow shipAddrs = new ShipAddressesWindow();
			
			EbazaarMainFrame.getInstance().getDesktop().add(shipAddrs);
			shipAddrs.setVisible(true);
			
		}
	}

	class ProceedFromBillingCheckoutListener implements ActionListener {
		CustomerSubsystem cust = 
			(CustomerSubsystem)SessionCache.getInstance().get(CustomerConstants.CUSTOMER);
		boolean rulesOk = true;
		String fullname;

		public void actionPerformed(ActionEvent evt) {
			boolean rulesOk = true;
			//not cleansed yet
			Address cleansedAddr = data.getShippingAddressFromWindow(shippingBillingWindow);
			Address billingAddress = data.getBillingAddressFromWindow(shippingBillingWindow);
			shippingBillingWindow.setVisible(false);
			if (data.isNewShippingAddress(shippingBillingWindow)) {
				//run address rules and obtain cleansed address 
				//save new address to db
				//set new address to shippingBillingWindow using setAddressFields method
				
			}
			// load into shopping cart and set up payment window
			if (rulesOk) {
				//cust.setBillingAddressInCart(billingAddress);
				//cust.setShippingAddressInCart(cleansedAddr);
				setupPaymentWindow();
			}
		}

		void setupPaymentWindow() {
			
			paymentWindow = new PaymentWindow();
			
			paymentWindow.setCredCardFields("","","","");
				
			
			EbazaarMainFrame.getInstance().getDesktop().add(paymentWindow);
			paymentWindow.setVisible(true);
			paymentWindow.setParentWindow(shippingBillingWindow);

		}
	}

	class BackToCartButtonListener implements ActionListener {
		public void actionPerformed(ActionEvent evt) {
			cartItemsWindow.setVisible(true);
			shippingBillingWindow.setVisible(false);
		}
	}

	// This allows user to select a shipping address
	class SelectAddressesListener implements ActionListener {

		public void actionPerformed(ActionEvent evt) {
			
			JTable table = shipAddressesWindow.getTable();
			try {
				//expect array of length 4: street, city, state, zip
				String[] vals = DataUtil.getSelectedRowFromTable(table);
				shipAddressesWindow.setVisible(false);
				String name = data.getFullName();
				if (shippingBillingWindow != null) {
					shippingBillingWindow.setShippingAddress(name, vals[0], vals[1], vals[2],vals[3]);
					shippingBillingWindow.setVisible(true);
				}
			} catch(UIException e) {
				MessagesUtil.displayErrorMsg(shipAddressesWindow, e.getMessage());
			}
			
		}
	}

	class CancelShipAddrListener implements ActionListener {
		public void actionPerformed(ActionEvent evt) {
			shippingBillingWindow.setVisible(true);
			shipAddressesWindow.dispose();
		}
	}

	// // control PaymentWindow
	class ProceedFromPaymentListener implements ActionListener {
		CustomerSubsystem cust = 
			(CustomerSubsystem)SessionCache.getInstance().get(CustomerConstants.CUSTOMER);

		public void actionPerformed(ActionEvent evt) {
			paymentWindow.setVisible(false);
			termsWindow = new TermsWindow();
			//run payment rules
			//set payment info in cart
			try {
				

				String termsText = data.extractTermsText();
				termsWindow.setTermsText(termsText);
				EbazaarMainFrame.getInstance().getDesktop().add(termsWindow);
				termsWindow.setVisible(true);

			} catch (ParseException e) {
				MessagesUtil.displayErrorMsg(paymentWindow,
						"Unable to display Terms and Conditions (parse error). Exiting");
				try {
					Thread.sleep(1200);
				} catch(InterruptedException ex) {
					//do nothing
				}
				System.exit(0);

			}
           
			//catch (RuleException e) {
			//	MessagesUtil.displayErrorMsg(paymentWindow, e.getMessage());
			//	paymentWindow.setVisible(true);
			//} 
		   
		}
	}

	class BackToCartFromPayListener implements ActionListener {
		public void actionPerformed(ActionEvent evt) {
			paymentWindow.setVisible(false);
			cartItemsWindow.setVisible(true);
		}

	}

	// // controlTermsWindow
	class AcceptTermsListener implements ActionListener {
		public void actionPerformed(ActionEvent evt) {
			finalOrderWindow = new FinalOrderWindow();
			EbazaarMainFrame.getInstance().getDesktop().add(finalOrderWindow);
			finalOrderWindow.setVisible(true);
			termsWindow.dispose();

		}

	}

	// // control FinalOrderWindow
	class SubmitFinalOrderListener implements ActionListener {
		public void actionPerformed(ActionEvent evt) {
			finalOrderWindow.setVisible(false);
			boolean rulesOk = true;
			//run final order rules
			
			if (rulesOk) {
				/*
				 * if rules pass, run the card through credit verificaiton
				 * system
				 */
				/* Do when all required data is available
				try {
					usecaseControl.verifyCreditCart(); //do this when data is available
				} catch (BusinessException e) {
					rulesOk = false;
					LOG.warning(e.getMessage());
					MessagesUtil.displayErrorMsg(finalOrderWindow, e.getMessage());
					finalOrderWindow.setVisible(false);
				}*/
			}
			if (rulesOk) {
				try {
					//submit order 
					String msg = data.extractGoodbyeMessage();
					termsWindow.setVisible(true);
					MessagesUtil.displayPlainMessage(finalOrderWindow, msg, "E-Bazaar: Thank You");
				//} catch (BackendException e) {
				//	String msg = "Unable to submit order at this time. Try again later.";
				//	MessagesUtil.displayErrorMsg(finalOrderWindow, msg);				
				} catch (ParseException e) {
					LOG.severe("Abnormal termination in SubmitFinalOrderListner...unable to read " +
							"and display final message.");
					String msg = "Order submitted but final message not displayed because of internal error.";
					MessagesUtil.displayErrorMsg(finalOrderWindow, msg);
				} finally {
					finalOrderWindow.dispose();

				}
			}
		}

	}

	class CancelFinalOrderListener implements ActionListener {
		public void actionPerformed(ActionEvent evt) {
			finalOrderWindow.setVisible(false);
			if (cartItemsWindow != null) {
				cartItemsWindow.setVisible(true);
			}
		}
	}
	
	// /////// PUBLIC INTERFACE -- for getting instances of listeners ///

	// CartItemsWindow
	public ActionListener getProceedToCheckoutListener(CartItemsWindow w) {
		return (new ProceedToCheckoutListener());
	}

	// ShippingBillingWindow
	public ActionListener getSelectShipButtonListener(ShippingBillingWindow w) {
		return (new SelectShipButtonListener());
	}

	public ActionListener getProceedFromBillingCheckoutListener(
			ShippingBillingWindow w) {
		return (new ProceedFromBillingCheckoutListener());
	}

	public ActionListener getBackToCartButtonListener(ShippingBillingWindow w) {
		return (new BackToCartButtonListener());
	}

	// ShipAddressesWindow

	public ActionListener getSelectAddressesListener(ShipAddressesWindow w) {
		return (new SelectAddressesListener());
	}

	public ActionListener getCancelShipAddrListener(ShipAddressesWindow w) {
		return (new CancelShipAddrListener());
	}

	// PaymentWindow

	public ActionListener getProceedFromPaymentListener(PaymentWindow w) {
		return (new ProceedFromPaymentListener());
	}

	public ActionListener getBackToCartFromPayListener(PaymentWindow w) {
		return (new BackToCartFromPayListener());
	}

	// TermsWindow
	public ActionListener getAcceptTermsListener(TermsWindow w) {
		return (new AcceptTermsListener());
	}

	// FinalOrderWindow
	public ActionListener getSubmitFinalOrderListener(FinalOrderWindow w) {
		return (new SubmitFinalOrderListener());
	}

	public ActionListener getCancelFinalOrderListener(FinalOrderWindow w) {
		return (new CancelFinalOrderListener());
	}

	// ////// PUBLIC ACCESSORS to register screens controlled by this class////

	public void setCartItemsWindow(CartItemsWindow w) {
		cartItemsWindow = w;
	}

	public void setShippingBillingWindow(ShippingBillingWindow w) {
		shippingBillingWindow = w;
	}

	public void setShipAddressesWindow(ShipAddressesWindow w) {
		shipAddressesWindow = w;
	}

	public void setPaymentWindow(PaymentWindow w) {
		paymentWindow = w;
	}

	public void setTermsWindow(TermsWindow w) {
		termsWindow = w;
	}

	public void setFinalOrderWindow(FinalOrderWindow w) {
		finalOrderWindow = w;
	}

	// ///// screens -- private references
	private CartItemsWindow cartItemsWindow;
	private ShippingBillingWindow shippingBillingWindow;
	private ShipAddressesWindow shipAddressesWindow;
	private PaymentWindow paymentWindow;
	private TermsWindow termsWindow;
	private FinalOrderWindow finalOrderWindow;
	private Window[] allWindows = {};
	private JInternalFrame[] internalFrames = { cartItemsWindow,
			shipAddressesWindow, shippingBillingWindow, cartItemsWindow,
			paymentWindow, termsWindow, finalOrderWindow };

	public void cleanUp() {
		ApplicationUtil.cleanup(allWindows);
		ApplicationUtil.cleanup(internalFrames);
	}

	
	
	public static CheckoutUIControl getInstance() {
		return INSTANCE;
	}
	private CheckoutUIControl() {
		//do nothing
	}
}
